/*
 * JBeagle - a Java toolkit for genetic algorithms.
 * 
 * Copyright (c) 2010 Matthijs Snel
 * 
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
package jbeagle.core;

import java.io.Serializable;
import java.util.AbstractCollection;
import java.util.Collection;

/**
 * Abstract implementation of the {@code Individual} interface.
 * <p>
 * Implements the {@code compareTo(Idividual<?>)} method to compare this {@code Individual}
 * to other {@code Individual}s based on fitness. It provides static methods to set the precision
 * used for the comparison, as explained in {@link #compareTo(Individual<?>)}.
 * <p>
 * Note: this class has a natural ordering that is probably inconsistent with equals, since
 * it leaves the specification of equals up to its subclasses; Individuals are ordered according
 * to fitness, but Individuals with the same fitness need not necessarily be equal.
 * <p>
 * Also overrides the {@code Collection} {@code add(E)} and {@code addAll(Collection<? extends E>)}
 * methods to check for any constraints implemented by the {@code Constraints} that can be specified
 * via the {@code setConstraints(Constraints<E>)} method. Classes implementing mutable {@code Individual}s
 * should override the {@code safeAdd(E)} and {@code safeAddAll(Collection<? extends E>)} methods, which
 * are called if the add operations do not violate the {@code Individual}'s constraints, if any.
 * <p>
 * Classes providing additional additive operations (e.g. {@code add(int, E)}, {@code put(E)},
 * {@code set(int, E)} etc., should ensure that constraints are checked properly and a 
 * {@code ConstraintViolatedException} is thrown if they are violated.
 * 
 * @author Matthijs Snel
 * @see AbstractCollection
 * @see Individual
 * @see Constraints
 * @see ConstraintViolatedException
 * @since 0.1
 *
 */
public abstract class AbstractIndividual<E> extends AbstractCollection<E> implements Individual<E>, Serializable {
	
	private static final long serialVersionUID = -4912909632079681356L;

	/** Static **/
	/**
	 * Specifies the precision with which comparisons will be carried out.
	 */
	protected static int 	precision = DEFAULT_COMPARE_PRECISION,
							scalingfactor = (int)Math.pow(10, precision);

	/**
	 * Gets the current precision used for comparison purposes.
	 * 
	 * @return the current precision
	 * @see #compareTo(Individual)
	 */
	public static int getComparePrecision() {
		return precision;
	}

	/**
	 * Sets the current precision used for comparison purposes.
	 * 
	 * @param p the desired precision
	 * @see #compareTo(Individual)
	 */
	public static void setComparePrecision(int p) {
		precision = p;
		scalingfactor = (int)Math.pow(10, precision);
	}
 
	
	
    /**
     * Constraints for this {@code Individual} (null in case no constraints were specified).   
     */
    protected Constraints<E> constraints;
    
    /**
     * The {@code Individual}'s current fitness score.
     */
	protected double fitness;
	
	/**
	 * Default constructor.
	 */
	protected AbstractIndividual() {
		setFitness(0);
	}
	
	/**
	 * Sets the constraints to the specified constraints.
	 * 
	 * @param constr The constraints.
	 */
    protected AbstractIndividual(Constraints<E> constr) {
    	constraints = constr;
        setFitness(0);
	}
    
	/**
	 * {@inheritDoc}
	 * 
	 * This implementation checks that the element to be added satisfies the {@code Constraints}
	 * posed on the {@code Individual}, if any. If it doesn't, it throws a
	 * {@code ConstraintViolatedException}. It it does, it calls method {@link #safeAdd(Object)}.
	 * 
	 * @throws ConstraintViolatedException if the provided element violates the constraints
	 * posed on the {@code Individual}
	 */
    @Override
	public boolean add(E e) {
		if( constraints != null && constraints.violates(e) )
			throw new ConstraintViolatedException(e.toString());
                
		return safeAdd(e);
	}
	
    /**
	 * {@inheritDoc}
	 * 
	 * This implementation checks that the collection to be added satisfies the {@code Constraints}
	 * posed on the {@code Individual}, if any. If it doesn't, it throws a
	 * {@code ConstraintViolatedException}, specifying which element was the first to violate
	 * the constraint. It it does, it calls method {@link #safeAddAll(Collection)}.
	 * 
	 * @throws ConstraintViolatedException if the provided element violates the constraints
	 * posed on the {@code Individual}
	 */
    @Override
    public boolean addAll(Collection<? extends E> c) {
        if( constraints != null ) {
            E e = constraints.violates(c);
            if( e != null )
                throw new ConstraintViolatedException(e.toString());
        }
        
        return safeAddAll(c);
    }
        
	/**
	 * Compares this Individual with the specified Individual for order. Returns a negative
	 * integer, zero, or a positive integer as the fitness of this Individual is less than,
	 * equal to, or greater than the fitness of the specified Individual.
	 * 
	 * This method detects fitness differences of up to {@code precision} decimal places. That is to say, if
	 * the absolute difference in fitness is less than 5/(10^(precision+1)), the method will not be able to
	 * detect that the two Individuals are different (it will return 0). The precision can be set
	 * by invoking the static method {@code setPrecision(int)}. By default it is set to 3.
	 * 
	 * For example, if the precision is 3, the method can detect fitness differences of
	 * 0.001 or above. However, since the difference is rounded, this amounts to detecting 
	 * differences of 0.0005 or above. If the precision is set to 2, the method will detect
	 * differences of 0.005 or above, and so on.
	 * 
	 * Note: this method imposes a natural ordering that is probably inconsistent with equals,
	 * since this class leaves the specification of equals up to its subclasses: Individuals with
	 * the same fitness need not necessarily be equal.
	 * 
	 * @param ind The Individual to compare to.
	 * @return a negative integer, zero, or a positive integer as the fitness of this Individual
	 * is less than, equal to, or greater than the fitness of the specified Individual.
	 */
	public int compareTo( Individual<?> ind ) {
		return (int) Math.round( scalingfactor * (fitness - ind.getFitness()) );
	}
	
	/**
	 * {@inheritDoc}
	 */
	public double getFitness() {
		return fitness;
	}
	
	/**
	 * Imposes a constraint on this {@code Individual} implemented by the provided
	 * {@code Constraints}. These constraints should be checked before anything is
	 * added to or replaced in the {@code Individual}.
	 * 
	 * @param c the constraints
	 */
    public void setConstraints(Constraints<E> c) {
        constraints = c;
    }
    
    /**
	 * {@inheritDoc}
	 */
	public void setFitness( double fitness ) {
		this.fitness = fitness;
	}
	
	/**
	 * Returns a string representation of this {@code Individual}. The string consists of
	 * the string representation of the {@code Individual}'s genes, in the order that they
	 * are returned by the {@code Individual}'s iterator. Each gene is separated by a space.
	 */
	@Override
	public String toString() {
		String s = "";
		for( E e : this )
			s += e.toString() + " ";
		return s.substring(0, s.length()-1);
	}
	
	/**
	 * Adds the specified element to this {@code Individual}. Subclasses can override this
	 * method to leave the constraint checking to the superclass.
	 * 
	 * @param e the element to be added.
	 * 
	 * @return true if the operation was succesful as per the contract of the 
	 * {@link Collection#add(Object)} method.
	 */
    protected boolean safeAdd(E e) {
        return super.add(e);
    }
    
    /**
	 * Adds the specified collection to this {@code Individual}. Subclasses can override this
	 * method to leave the constraint checking to the superclass.
	 * 
	 * @param c the collection to be added.
	 * 
	 * @return true if the operation was succesful as per the contract of the 
	 * {@link Collection#addAll(Collection)} method.
	 */
    protected boolean safeAddAll(Collection<? extends E> c) {
        return super.addAll(c);
    }
}
